package com.fcscs.cservice.service.impl;

import java.util.List;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.fcscs.core.common.ErrorEnums;
import com.fcscs.core.service.FcsManager;
import com.fcscs.cservice.common.CServiceCommonEnums.ModuleEnum;
import com.fcscs.cservice.common.CServiceCommonEnums.UpdateVerLevelEnum;
import com.fcscs.cservice.common.CServiceCommonEnums.VersionEntityTypeEnum;
import com.fcscs.cservice.common.CServiceCommonEnums.VersionTypeEnum;
import com.fcscs.cservice.dao.ECMSVersionDao;
import com.fcscs.cservice.domain.VersionUpdates;
import com.fcscs.cservice.domain.Versions;
import com.fcscs.cservice.domain.model.EntityVersionView;
import com.fcscs.cservice.domain.model.VersionView;
import com.fcscs.cservice.domain.validator.VersionValidators;
import com.fcscs.cservice.service.ECMSInRoomMenuManager;
import com.fcscs.cservice.service.ECMSVersionManager;
import com.fcscs.cservice.service.VersionableManager;
import com.fcscs.ecms.service.ECMSMainMenuManager;
import com.fcscs.ecms.service.ECMSRestaurantManager;
import com.fcscs.ecms.service.ECMSThemeManager;
import com.ibm.icu.util.Calendar;

@Service("ecmsVersionManager")
public class ECMSVersionManagerImpl extends FcsManager implements ECMSVersionManager {
	private static final long serialVersionUID = -1616190660654588749L;

	@Autowired
	ECMSVersionDao vDao;
	@Autowired
	ECMSInRoomMenuManager inRoomMgr;
	@Autowired
	com.fcscs.ecms.service.ECMSAdvertiseManager advMgr;
	@Autowired
	ECMSMainMenuManager mMenuMgr;
	@Autowired
	ECMSThemeManager themeMgr;
	@Autowired
	ECMSRestaurantManager restMgr;

	private static Logger LOGGER = Logger.getLogger(ECMSVersionManagerImpl.class);
	
	private static boolean autoCreateCurrentVersion = true;
	private static boolean autoCreateScheduledVersion = true;

	private VersionableManager getModuleManager(ModuleEnum module) {
		switch (module) {
		case RESTAURANT: return (VersionableManager) restMgr;
		case MAIN_MENU: return (VersionableManager) mMenuMgr;
		case THEME: return (VersionableManager) themeMgr;
		case ADVERTISEMENT: return (VersionableManager) advMgr;
		case IN_ROOM_DINING: return (VersionableManager) inRoomMgr;
		default: return null;
		}
	}

	@Override
	public List<Versions> getVersions(long orgId, long propId, ModuleEnum module, VersionTypeEnum versionType, VersionEntityTypeEnum entityType) {
		return vDao.getVersions(orgId, propId, module, versionType, entityType);
	}

	@Override
	public Versions createVersion(long orgId, long propId, Versions ver) {
		if (ver == null) {
			return ver;
		}
		Versions newObj = new Versions();
		newObj.setOrgId(orgId);
		newObj.setPropertyId(propId);
		newObj.setModuleEnum(ver.getModuleEnum());
		newObj.setVersionTypeEnum(ver.getVersionTypeEnum());
		newObj.setEntityTypeEnum(ver.getEntityTypeEnum());
		newObj.setTemplateName(ver.getTemplateName());
		newObj.setStartDate(ver.getStartDate());
		ErrorEnums err = new VersionValidators.VersionsValidator().validate(newObj, true);
		if (err != null) {
			LOGGER.debug(err);
			return null;
		}
		if (vDao.isVersionTaken(newObj.getOrgId(), newObj.getPropertyId(), newObj.getModuleEnum(), newObj.getVersionTypeEnum(),
				newObj.getEntityTypeEnum(), newObj.getTemplateName(), null)) {
			LOGGER.debug(ErrorEnums.GeneralError.UNIQUE_CONS + ": " + newObj.getModuleEnum() + "-" + newObj.getVersionTypeEnum() + "-" + newObj.getEntityTypeEnum());
			return null;
		}
		transferBaseVals(ver, newObj, true);
		newObj = vDao.saveVersion(newObj);
		if (VersionTypeEnum.CURRENT.equals(newObj.getVersionTypeEnum())) {
			VersionUpdates vu = new VersionUpdates();
			vu.setOrgId(orgId);
			vu.setPropertyId(propId);
			vu.setModuleEnum(newObj.getModuleEnum());
			vu.setVersionValue(0L);
			vu = createVersionUpdates(orgId, propId, vu);
			List<VersionEntityTypeEnum> entityTypeList = newObj.getModuleEnum().getEntityTypeList();
			for (VersionEntityTypeEnum type : entityTypeList) {
				vu = new VersionUpdates();
				vu.setOrgId(orgId);
				vu.setPropertyId(propId);
				vu.setModuleEnum(newObj.getModuleEnum());
				vu.setEntityTypeEnum(type);
				vu.setVersionValue(0L);
				vu = createVersionUpdates(orgId, propId, vu);
			}
		}
		return newObj;
	}
	
	public VersionUpdates createVersionUpdates(long orgId, long propId, VersionUpdates vu) {
		if (vu == null) {
			return vu;
		}
		VersionUpdates newObj = new VersionUpdates();
		newObj.setOrgId(orgId);
		newObj.setPropertyId(propId);
		newObj.setModuleEnum(vu.getModuleEnum());
		newObj.setEntityTypeEnum(vu.getEntityTypeEnum());
		newObj.setEntityId(vu.getEntityId());
		newObj.setVersionValue(0L);
		ErrorEnums err = new VersionValidators.VersionUpdatesValidator().validate(newObj, true);
		if (err != null) {
			LOGGER.debug(err);
			return null;
		}
		if (vDao.isVersionUpdatesTaken(orgId, propId, newObj.getModuleEnum(), newObj.getEntityTypeEnum(), newObj.getEntityId(), null)) {
			LOGGER.debug(ErrorEnums.GeneralError.UNIQUE_CONS + ": " + newObj.getModuleEnum() + "-" + newObj.getEntityTypeEnum() + "-" + newObj.getEntityId());
			return null;
		}
		transferBaseVals(vu, newObj, true);
		newObj = vDao.saveVersionUpdates(newObj);
		return newObj;
	}

	@Override
	public boolean deleteVersion(Versions ver) {
		return vDao.deleteVersion(ver);
	}

	@Override
	public boolean deleteVersionUpdates(VersionUpdates vu) {
		return vDao.deleteVersionUpdates(vu);
	}

	@Override
	public boolean permDeleteVersion(Versions ver) {
		return vDao.permDeleteVersion(ver);
	}

	@Override
	public boolean permDeleteVersionUpdates(VersionUpdates vu) {
		return vDao.permDeleteVersionUpdates(vu);
	}

	@Override
	public boolean isVersionTaken(long orgId, long propId, ModuleEnum module, VersionTypeEnum versionType, VersionEntityTypeEnum entityType, String name, Long id) {
		return vDao.isVersionTaken(orgId, propId, module, versionType, entityType, name, id);
	}

	@Override
	public Versions saveToTemplate(long orgId, long propId, Versions fromVer, Versions toVer) {
		ModuleEnum module = toVer.getModuleEnum();
		if (!VersionTypeEnum.TEMPLATE.equals(toVer.getVersionTypeEnum())) {
			LOGGER.debug("can not save to a non template version " + toVer.getVersionTypeEnum());
		}
		Versions tmplVer = getVersion(orgId, propId, module, toVer.getVersionTypeEnum(), toVer.getTemplateName());
		if (tmplVer == null) {
			tmplVer = createVersion(orgId, propId, toVer);
		}
		VersionableManager mgr = getModuleManager(module);
		if (mgr.copyVersion(fromVer, tmplVer)) {
			return tmplVer;
		}
		return null;
	}

	@Override
	public Versions copyFromTemplate(long orgId, long propId, Versions fromVer, Versions toVer) {
		VersionTypeEnum cOrSType = toVer.getVersionTypeEnum();
		ModuleEnum module = toVer.getModuleEnum();
		if (!VersionTypeEnum.CURRENT.equals(cOrSType) && !VersionTypeEnum.SCHEDULED.equals(cOrSType)) {
			LOGGER.debug("can not load template to a non template non scheduled version " + cOrSType);
		}
		vDao.invalidateVersion(toVer, VersionTypeEnum.OVERWRITTEN, VersionTypeEnum.CURRENT.equals(cOrSType));
		Versions newVer = new Versions();
		newVer.setOrgId(orgId);
		newVer.setPropertyId(propId);
		newVer.setModuleEnum(module);
		newVer.setVersionTypeEnum(cOrSType);
		newVer.setEntityTypeEnum(toVer.getEntityTypeEnum());
		newVer.setStartDate(toVer.getStartDate());
		newVer = createVersion(orgId, propId, newVer);
		VersionableManager mgr = getModuleManager(module);
		if (mgr.copyVersion(fromVer, newVer)) {
			return newVer;
		}
		return null;
	}

	@Override
	public List<Versions> getExpiredVersionList(long orgId, long propId) {
		return vDao.getExpiredVersionList(orgId, propId);
	}

	@Override
	public boolean expireCurrent(long orgId, long propId, Versions oldScheduled, Versions oldCurrent) {
		ModuleEnum module = oldCurrent.getModuleEnum();
		if (!VersionTypeEnum.CURRENT.equals(oldCurrent.getVersionTypeEnum())
				|| !VersionTypeEnum.SCHEDULED.equals(oldScheduled.getVersionTypeEnum())) {
			LOGGER.debug("invalid version type, scheduled=" + oldScheduled.getVersionTypeEnum() + ", current=" + oldCurrent.getVersionTypeEnum());
		}
		vDao.invalidateVersion(oldCurrent, VersionTypeEnum.EXPIRED, true);
		Versions newVer = new Versions();
		newVer.setOrgId(orgId);
		newVer.setPropertyId(propId);
		newVer.setModuleEnum(module);
		newVer.setVersionTypeEnum(VersionTypeEnum.CURRENT);
		newVer.setEntityTypeEnum(oldCurrent.getEntityTypeEnum());
		newVer.setStartDate(oldCurrent.getStartDate());
		newVer = createVersion(orgId, propId, newVer);
		vDao.deleteVersion(oldScheduled);
		VersionableManager mgr = getModuleManager(module);
		if (mgr.copyVersion(oldScheduled, newVer)) {
			return true;
		}
		return false;
	}

	@Override
	public List<VersionView> getVersionViewList(long orgId, long propId, ModuleEnum module, List<VersionView> verList) {
		return vDao.getVersionViewList(orgId, propId, module, verList);
	}

	@Override
	public List<EntityVersionView> getEntityVersionViewList(long orgId, long propId, ModuleEnum module) {
		return getModuleManager(module).getEntityVersionViewList(orgId, propId);
	}

	@Override
	public void updateVersionValues(long orgId, long propId, ModuleEnum module, VersionEntityTypeEnum entityType, Long entityId, UpdateVerLevelEnum level) {
		vDao.updateVersionValues(orgId, propId, module, entityType, entityId, level);
	}

	@Override
	public Versions getCurrentVersion(long orgId, long propId, ModuleEnum module) {
		return getCurrentVersion(orgId, propId, module, autoCreateCurrentVersion);
	}

	@Override
	public Versions getCurrentVersion(long orgId, long propId, ModuleEnum module, boolean autoCreate) {
		Versions v = vDao.getCurrentVersion(orgId, propId, module, null);
		if (v == null && autoCreate) {
			v = new Versions();
			v.setOrgId(orgId);
			v.setPropertyId(propId);
			v.setModuleEnum(module);
			v.setVersionTypeEnum(VersionTypeEnum.CURRENT);
			v = createVersion(orgId, propId, v);
		}
		return v;
	}

	@Override
	public Versions getScheduledVersion(long orgId, long propId, ModuleEnum module) {
		return getScheduledVersion(orgId, propId, module, autoCreateScheduledVersion);
	}

	@Override
	public Versions getScheduledVersion(long orgId, long propId, ModuleEnum module, boolean autoCreate) {
		Versions v = vDao.getScheduledVersion(orgId, propId, module, null);
		if (v == null && autoCreate) {
			v = new Versions();
			v.setOrgId(orgId);
			v.setPropertyId(propId);
			v.setModuleEnum(module);
			v.setVersionTypeEnum(VersionTypeEnum.SCHEDULED);
			Calendar c = Calendar.getInstance();
			c.set(Calendar.YEAR, 9999);//c.getActualMaximum(Calendar.YEAR));
			v.setStartDate(c.getTime());
			v = createVersion(orgId, propId, v);
		}
		return v;
	}

	@Override
	public Versions getVersion(long orgId, long propId, ModuleEnum module, VersionTypeEnum versionType, String name) {
		return vDao.getVersion(orgId, propId, module, versionType, null, name);
	}

	@Override
	public List<VersionUpdates> getVersionUpdates(long orgId, long propId, ModuleEnum module, VersionEntityTypeEnum entityType) {
		return vDao.getVersionUpdates(orgId, propId, module, entityType);
	}
}
